//
//  ES1Renderer.m
//  MathMastersAsteroids
//
//  Created by Jordon Phillips on 3/1/10.
//  Copyright __MyCompanyName__ 2010. All rights reserved.
//

#import "ES1Renderer.h"

@implementation ES1Renderer

//setups the textures to be used by the game
-(void)setupTextures{
	//Generate textures: first parameter is the number of textures you are going to use, you must also change the array size in ES1Renderer.h
	glGenTextures(21, &texture[0]); 
	//load textures
	[self loadTexture:@"stars.png" intoLocation:texture[0]];
	[self loadTexture:@"spaceship.png" intoLocation:texture[1]];
	[self loadTexture:@"asteroid.png" intoLocation:texture[2]];
	[self loadTexture:@"0.png" intoLocation:texture[3]];
	[self loadTexture:@"1.png" intoLocation:texture[4]];
	[self loadTexture:@"2.png" intoLocation:texture[5]];
	[self loadTexture:@"3.png" intoLocation:texture[6]];
	[self loadTexture:@"4.png" intoLocation:texture[7]];
	[self loadTexture:@"5.png" intoLocation:texture[8]];
	[self loadTexture:@"6.png" intoLocation:texture[9]];
	[self loadTexture:@"7.png" intoLocation:texture[10]];
	[self loadTexture:@"8.png" intoLocation:texture[11]];
	[self loadTexture:@"9.png" intoLocation:texture[12]];
	[self loadTexture:@"bullet.png" intoLocation:texture[13]];
	[self loadTexture:@"asteroidsGui.png" intoLocation:texture[14]];
	[self loadTexture:@"asteroidsGuiBack.png" intoLocation:texture[15]];
	[self loadTexture:@"asteroidsGuiHealth.png" intoLocation:texture[16]];
	[self loadTexture:@"asteroidsGuiTime.png" intoLocation:texture[17]];
	[self loadTexture:@"correct.png" intoLocation:texture[18]];
	[self loadTexture:@"wrong.png" intoLocation:texture[19]];
	[self loadTexture:@"numberExplode.png" intoLocation:texture[20]];
	[self loadTexture:@"starfield.png" intoLocation:texture[21]];
}

//loads a texture from an image file
- (void)loadTexture:(NSString *)name intoLocation:(GLuint)location {
	
	CGImageRef textureImage = [UIImage imageNamed:name].CGImage;
	if (textureImage == nil) {
        NSLog(@"Failed to load texture image");
		return;
    }
	
    NSInteger texWidth = CGImageGetWidth(textureImage);
    NSInteger texHeight = CGImageGetHeight(textureImage);
	
	GLubyte *textureData = (GLubyte *)malloc(texWidth * texHeight * 4);
	
    CGContextRef textureContext = CGBitmapContextCreate(textureData,
														texWidth, texHeight,
														8, texWidth * 4,
														CGImageGetColorSpace(textureImage),
														kCGImageAlphaPremultipliedLast);
	
	// Rotate the image
	CGContextTranslateCTM(textureContext, 0, texHeight);
	CGContextScaleCTM(textureContext, 1.0, -1.0);
	
	CGContextDrawImage(textureContext, CGRectMake(0.0, 0.0, (float)texWidth, (float)texHeight), textureImage);
	CGContextRelease(textureContext);
	
	glBindTexture(GL_TEXTURE_2D, location);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
	
	free(textureData);
	
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
}

// Create an ES 1.1 context
- (id) init
{
	if (self = [super init])
	{
		context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
        
        if (!context || ![EAGLContext setCurrentContext:context])
		{
            [self release];
            return nil;
        }
		
		// Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
		glGenFramebuffersOES(1, &defaultFramebuffer);
		glGenRenderbuffersOES(1, &colorRenderbuffer);
		glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
		glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
		glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
		glDisable(GL_DEPTH_TEST);
		glEnable(GL_TEXTURE_2D);
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_ALPHA_TEST);
		glAlphaFunc(GL_NOTEQUAL, 0);
		//initilize sprite list
		sprites = [[NSMutableArray alloc] init];
		
		//setup textures
		[self setupTextures];
	
		
	}
	
	return self;
}

//renders a frame
- (void) render
{
    // Replace the implementation of this method to do your own custom drawing
    
    static const GLfloat squareVertices[] = {
        -0.5f,  -0.5f,
         0.5f,  -0.5f,
        -0.5f,   0.5f,
         0.5f,   0.5f,
    };
	static const GLfloat textCoords[] = {
		0.8,1,
		0.8,0.8,
		1,1,
		1,0.8,
	};
    
	
	// This application only creates a single context which is already set current at this point.
	// This call is redundant, but needed if dealing with multiple contexts.
    [EAGLContext setCurrentContext:context];
    
	// This application only creates a single default framebuffer which is already bound at this point.
	// This call is redundant, but needed if dealing with multiple framebuffers.
    glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
    glViewport(0, 0, backingWidth, backingHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
    
	
    glClearColor(0, 0, 0, 0);
    glClear(GL_COLOR_BUFFER_BIT);
	glOrthof(100, 0, 150, 0, 0, 1);
	glColor4f(1,1,1,1);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	//draw all sprites in array
	for(Sprite *s in sprites) {
		if(!s.dead){
			int frame=0;
			int dim=1;
			if(s.animated){
				frame=s.currentFrame;
				dim=s.frameDim;
			}
			GLfloat frameDim=(10000/dim)*0.0001;//float percision control doesnt work properly if full float lenght is used
			GLfloat yFrame=(int)(frame/dim);
			GLfloat xFrame=frame%dim;
			GLfloat frameCoords[] = {
				((xFrame)*frameDim),1-(yFrame*frameDim),
				((xFrame)*frameDim),1-((yFrame+1)*frameDim),
				((xFrame+1)*frameDim),1-(yFrame*frameDim),
				((xFrame+1)*frameDim),1-((yFrame+1)*frameDim),
			};
			glBindTexture(GL_TEXTURE_2D, texture[s.image]);
			glTranslatef(s.yPos,s.xPos,0);
			glScalef(s.scale, s.scale, s.scale);
			glVertexPointer(2, GL_FLOAT, 0, squareVertices);
			glTexCoordPointer(2, GL_FLOAT, 0, frameCoords);
			glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
			GLfloat oldScale = (1/s.scale);
			glScalef(oldScale, oldScale, oldScale);
			glTranslatef(-s.yPos,-s.xPos,0);
		}
		
	}
    
	// This application only creates a single color renderbuffer which is already bound at this point.
	// This call is redundant, but needed if dealing with multiple renderbuffers.
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
    [context presentRenderbuffer:GL_RENDERBUFFER_OES];
}

- (BOOL) resizeFromLayer:(CAEAGLLayer *)layer
{	
	// Allocate color buffer backing based on the current layer size
    glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
    [context renderbufferStorage:GL_RENDERBUFFER_OES fromDrawable:layer];
	glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_WIDTH_OES, &backingWidth);
    glGetRenderbufferParameterivOES(GL_RENDERBUFFER_OES, GL_RENDERBUFFER_HEIGHT_OES, &backingHeight);
	
    if (glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES) != GL_FRAMEBUFFER_COMPLETE_OES)
	{
		NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES));
        return NO;
    }
    
    return YES;
}

- (void) dealloc
{
	// Tear down GL
	if (defaultFramebuffer)
	{
		glDeleteFramebuffersOES(1, &defaultFramebuffer);
		defaultFramebuffer = 0;
	}

	if (colorRenderbuffer)
	{
		glDeleteRenderbuffersOES(1, &colorRenderbuffer);
		colorRenderbuffer = 0;
	}
	
	// Tear down context
	if ([EAGLContext currentContext] == context)
        [EAGLContext setCurrentContext:nil];
	[sprites release];
	[context release];
	context = nil;
	
	[super dealloc];
}

//adds a sprite to the sprite list
- (void) addSprite:(Sprite *)sprite
{
	for(Sprite *s in sprites) {
		if(s.dead){
			s=sprite;
			return;
		}
	}
	[sprites addObject:sprite];
}

@end
